#coding=utf-8
from twisted.internet.protocol import Protocol, ClientFactory, ServerFactory
from twisted.internet import reactor
from zope.interface import implements, Interface
import struct, Queue
from threading import Thread

from log import log
import sys

try:
    import cStringIO as StringIO
except ImportError:
    import StringIO

import tools
from Account import accounts
from Route import routeTable

RESEND_SECOND = 30
ACTIVE_SECOND = 60

TEST = 0x00000001
TEST_RESP = 0x80000001
SUBMIT = 0x00000002
SUBMIT_RESP = 0x80000002
LOGIN = 0x00000003
LOGIN_RESP = 0x80000003

TEST_LENGTH = 12
TEST_RESP_LENGTH = 12
SUBMIT_LENGTH = 55
SUBMIT_RESP_LENGTH = 16
LOGIN_LENGTH = 32
LOGIN_RESP_LENGTH = 16
class DemoParseError(ValueError):
    pass

class IEncodable(Interface):
    def encode(strio, compDict = None):
        pass
    
    def decode(strio, length = None):
        pass

class DemoUtil(object):
    @staticmethod
    def strtobcd(strin):
        bcd = StringIO.StringIO()
        flag = False
        for b in strin:
            if flag:
                tmp |= int(b) 
                bcd.write(chr(tmp))
                flag = False
            else:                
                tmp = int(b) << 4
                flag = True
            
        return bcd.getvalue()
    
    @staticmethod
    def makeTest():
        return DemoTest()
    
    @staticmethod
    def makeTestResp(m):
        p = DemoTestResp()
        p.sequenceID = m.sequenceID
        return p

    @staticmethod
    def makeSubmit(src, dst, content):
        m = DemoSubmit()
        m.srcmobile = src
        m.dstmobile = dst
        m.msgLength = len(content)
        m.msgContent = content
        m.packetLength = m.packetLength + len(content)
        return m
    @staticmethod
    def makeSubmitResp(m):
        p = DemoSubmitResp()
        p.sequenceID = m.sequenceID
        return p

    @staticmethod
    def makeLogin(username, password):
        m = DemoLogin()
        m.username = username
        m.password = password
        return m
    @staticmethod
    def makeLoginResp(m):
        p = DemoLoginResp()
        p.sequenceID = m.sequenceID
        return p
    
class SeqGen(object):
    seqID = 0
    @staticmethod
    def nextID():
        SeqGen.seqID = SeqGen.seqID + 1
        return SeqGen.seqID
      
   
class DemoHeader(object):
    implements(IEncodable)
    
    def __init__(self, packetLength = 12, requestID = TEST, sequenceID = 1): 
        self.packetLength = packetLength
        self.requestID = requestID
        self.sequenceID = sequenceID 

    def encode(self, strio, compDict = None):
        format = '!3I'
        strio.write(
            struct.pack(format, self.packetLength, self.requestID, self.sequenceID))

    def decode(self, strio, length = None):
        format = '!3I'
        self.packetLength, self.requestID, self.sequenceID = struct.unpack_from(format, strio.getvalue())

    def toStr(self):
        strio = StringIO.StringIO()
        self.encode(strio)
        return strio.getvalue()

    def fromStr(self, str):
        strio = StringIO.StringIO(str)
        self.decode(strio)
        
class DemoTest(DemoHeader):
    def __init__(self):
        DemoHeader.__init__(self, TEST_LENGTH, TEST, SeqGen.nextID())

class DemoTestResp(DemoHeader):
    def __init__(self, sequenceID = 0):
        DemoHeader.__init__(self, TEST_RESP_LENGTH, TEST_RESP, sequenceID)

class DemoSubmit(DemoHeader):
    def __init__(self):
        DemoHeader.__init__(self, SUBMIT_LENGTH, SUBMIT, SeqGen.nextID())
        self.srcmobile = ''
        self.dstmobile = ''
        self.msgLength = 0
        self.msgContent = ''
        
    
    def encode(self, strio, compDict = None):
        DemoHeader.encode(self, strio)
        format = '!21s21sB'
        strio.write(struct.pack(format, self.srcmobile,
            self.dstmobile,
            self.msgLength))
        temp = str(self.msgLength)
        format = '!' + temp + 's'
        strio.write(struct.pack(format, self.msgContent))
         
    def decode(self, strio, length = None):
        DemoHeader.decode(self, strio)
        format = '!21s21sB' 
        (self.srcmobile,
            self.dstmobile,
            self.msgLength) = struct.unpack_from(format, strio.getvalue(), 12)
        s = struct.calcsize(format)
        format = '!' + str(self.msgLength) + 's'
        (self.msgContent,) = struct.unpack_from(format, strio.getvalue(), 12 + s)
        
class DemoSubmitResp(DemoHeader):
    def __init__(self, sequenceID = 0):
        DemoHeader.__init__(self, SUBMIT_RESP_LENGTH, SUBMIT_RESP, sequenceID)
        self.status = 0
  
    def encode(self, strio, compDict = None):
        DemoHeader.encode(self, strio)
        format = '!I'
        strio.write(struct.pack(format, self.status))
         
    def decode(self, strio, length = None):
        DemoHeader.decode(self, strio)
        format = '!I' 
        (self.status,) = struct.unpack_from(format, strio.getvalue(), 12)
        

class DemoLogin(DemoHeader):
    def __init__(self):
        DemoHeader.__init__(self, LOGIN_LENGTH, LOGIN, SeqGen.nextID())
        self.username = ''
        self.password = ''        
    
    def encode(self, strio, compDict = None):
        DemoHeader.encode(self, strio)
        format = '!10s10s'
        strio.write(struct.pack(format, self.username,
            self.password))
         
    def decode(self, strio, length = None):
        DemoHeader.decode(self, strio)
        format = '!10s10s' 
        (self.username,
            self.password) = struct.unpack_from(format, strio.getvalue(), 12)
        
class DemoLoginResp(DemoHeader):
    def __init__(self, sequenceID = 0):
        DemoHeader.__init__(self, LOGIN_RESP_LENGTH, LOGIN_RESP, sequenceID)
        self.status = 0
  
    def encode(self, strio, compDict = None):
        DemoHeader.encode(self, strio)
        format = '!I'
        strio.write(struct.pack(format, self.status))
         
    def decode(self, strio, length = None):
        DemoHeader.decode(self, strio)
        format = '!I' 
        (self.status,) = struct.unpack_from(format, strio.getvalue(), 12)
        
                
class DemoProtocol(Protocol):
    """This is Demo Protocol!"""
    def __init__(self):
        self.header = DemoHeader()
        self.buffer = ''
    
    def writeMessage(self, message):
        s = message.toStr()
        #log.debug(tools.bin2hexstr(s))
        
        self.transport.write(s)
        
    
    
    def dataReceived(self, data):
        self.buffer += data
        
        while self.buffer:
            if len(self.buffer) >= 12:
                self.header.fromStr(self.buffer[:12])
                
            if len(self.buffer) >= self.header.packetLength:
                myChunk = self.buffer[:self.header.packetLength]
                #log.debug(tools.bin2hexstr(myChunk))
                if self.header.requestID == TEST:
                    m = DemoTest()
                elif self.header.requestID == TEST_RESP:
                    m = DemoTestResp()
                elif self.header.requestID == SUBMIT:
                    m = DemoSubmit()
                elif self.header.requestID == SUBMIT_RESP:
                    m = DemoSubmitResp()
                elif self.header.requestID == LOGIN:
                    m = DemoLogin()
                elif self.header.requestID == LOGIN_RESP:
                    m = DemoLoginResp()
                else:
                    raise DemoParseError
                
                m.fromStr(myChunk)
                #log.debug(str(m))
                self.handler.recvMsg(m)
                self.buffer = self.buffer[self.header.packetLength:]
                self.header.packetLength = 12
            else:
                break

class DemoClientProtocol(DemoProtocol):
    def connectionMade(self):
        """init a handler"""
        log.debug('Client connection made')
        self.handler = DemoClientHandler(self)
        self.factory.handlerList.append(self.handler)
        
class DemoServerProtocol(DemoProtocol):
    def connectionMade(self):
        """init a handler"""
        log.debug('accept a connection')
        self.handler = DemoServerHandler(self)
        self.factory.handlerList.append(self.handler)
        
class DemoClientFactory(ClientFactory):
    def __init__(self):
        self.protocol = DemoClientProtocol
        self.handlerList = []
        
    def startedConnecting(self, connector):
        log.debug('started connectioning')
            

class DemoServerFactory(ServerFactory):
    def __init__(self):
        self.protocol = DemoServerProtocol
        self.handlerList = []
        
    def startedConnecting(self, connector):
        log.debug('started connectioning')
        

class DemoClientHandler(object):
    def __init__(self, p):
        self.p = p
        self.recvQueue = Queue.Queue(0)
        self.sendQueue = Queue.Queue(0)
        self.sendedDict = {}
        self.recvFlag = True
        self.sendFlag = True
        
        self.activeCaller = reactor.callLater(ACTIVE_SECOND, self.activeMessage)
        self.handleRecvThread = Thread(target = self.handleRecv)
        self.handleRecvThread.start()
        self.handleSendThread = Thread(target = self.handleSend)
        self.handleSendThread.start()
        
        
        
    def submitMessage(self, message):
        self.sendQueue.put(message)
        
    def sendMessage(self, message):
        caller, times = self.sendedDict.get(message.sequenceID, [None, 0])
        if caller == None:
            caller = reactor.callLater(RESEND_SECOND, self.resendMessage, message)
            self.sendedDict[message.sequenceID] = [caller, 1]
            self.p.writeMessage(message)
        else:
            caller = reactor.callLater(RESEND_SECOND, self.resendMessage, message)
            self.sendedDict[message.sequenceID] = [caller, times + 1]
            self.p.writeMessage(message)
            
    def resendMessage(self, message):
        caller, times = self.sendedDict.get(message.sequenceID, [None, 0])
        if times < 3:
            self.submitMessage(message)
        else:
            self.sendedDict.pop(message.sequenceID, None)
        
    def activeMessage(self):
        m = DemoUtil.makeTest()
        self.submitMessage(m)
        self.activeCaller = reactor.callLater(ACTIVE_SECOND, self.activeMessage)
        
    def handleRecv(self):
        while self.recvFlag:
            try:
                m = self.recvQueue.get()
                self.activeCaller.reset(ACTIVE_SECOND)
                log.debug('get recvQueue m:' + tools.bin2hexstr(m.toStr()))
                if m.requestID == TEST:
                    resp = DemoUtil.makeTestResp(m)
                    self.submitMessage(resp)
                    log.debug('recv Test Message')
                    
                elif m.requestID == TEST_RESP:
                    caller, times = self.sendedDict.get(m.sequenceID, [None, 0])
                    if caller != None:
                        caller.cancel()
                        self.sendedDict.pop(m.sequenceID, None)
                    log.debug('recv Test Resp Message')
                
                elif m.requestID == SUBMIT:
                    resp = DemoUtil.makeSubmitResp(m)
                    self.submitMessage(resp)
                    log.debug('recv Submit Message')
                    
                elif m.requestID == SUBMIT_RESP:
                    caller, times = self.sendedDict.get(m.sequenceID, [None, 0])
                    if caller != None:
                        caller.cancel()
                        self.sendedDict.pop(m.sequenceID, None)
                    log.debug('recv Submit Resp Message')
                elif m.requestID == LOGIN:
                    resp = DemoUtil.makeLoginResp(m)
                    self.submitMessage(resp)
                    log.debug('recv Login Message')
                    
                elif m.requestID == LOGIN_RESP:
                    caller, times = self.sendedDict.get(m.sequenceID, [None, 0])
                    if caller != None:
                        caller.cancel()
                        self.sendedDict.pop(m.sequenceID, None)
                    log.debug('recv Login Resp Message')
                else:
                    pass
            except:
                pass
                
    def handleSend(self):
        while self.sendFlag:
            try:
                m = self.sendQueue.get()
                self.activeCaller.reset(ACTIVE_SECOND)
                log.debug('get sendQueue m:' + tools.bin2hexstr(m.toStr()))
                if m.requestID == TEST:
                    self.sendMessage(m)
                    log.debug('send Test Message')
                elif m.requestID == TEST_RESP:
                    self.p.writeMessage(m)
                    log.debug('send Test Resp Message')
                elif m.requestID == SUBMIT:
                    self.sendMessage(m)
                    log.debug('send Submit Message')
                elif m.requestID == SUBMIT_RESP:
                    self.p.writeMessage(m)
                    log.debug('send Submit Resp Message')
                elif m.requestID == LOGIN:
                    self.sendMessage(m)
                    log.debug('send Login Message')
                elif m.requestID == LOGIN_RESP:
                    self.p.writeMessage(m)
                    log.debug('send Login Resp Message')
                
                else:
                    pass
            except:
                pass
                
       
    def recvMsg(self, message):
        """
        TODO:
        """
        try:
            self.recvQueue.put(message)
        except:
            log.debug(str(sys.exc_info()))
        
        
class DemoServerHandler(object):
    def __init__(self, p):
        self.p = p
        self.recvQueue = Queue.Queue(0)
        self.sendQueue = Queue.Queue(0)
        self.sendedDict = {}
        self.recvFlag = True
        self.sendFlag = True
        
        self.activeCaller = reactor.callLater(ACTIVE_SECOND + 1, self.activeMessage)
        self.handleRecvThread = Thread(target = self.handleRecv)
        self.handleRecvThread.start()
        self.handleSendThread = Thread(target = self.handleSend)
        self.handleSendThread.start()
        
        
        
    def submitMessage(self, message):
        self.sendQueue.put(message)
        
    def sendMessage(self, message):
        caller, times = self.sendedDict.get(message.sequenceID, [None, 0])
        if caller == None:
            caller = reactor.callLater(RESEND_SECOND, self.resendMessage, message)
            self.sendedDict[message.sequenceID] = [caller, 1]
            self.p.writeMessage(message)
        else:
            caller = reactor.callLater(RESEND_SECOND, self.resendMessage, message)
            self.sendedDict[message.sequenceID] = [caller, times + 1]
            self.p.writeMessage(message)
            
    def resendMessage(self, message):
        caller, times = self.sendedDict.get(message.sequenceID, [None, 0])
        if times < 3:
            self.submitMessage(message)
        else:
            self.sendedDict.pop(message.sequenceID, None)
        
    def activeMessage(self):
        m = DemoUtil.makeTest()
        self.submitMessage(m)
        self.activeCaller = reactor.callLater(ACTIVE_SECOND + 1, self.activeMessage)
        
    def handleRecv(self):
        while self.recvFlag:
            try:
                m = self.recvQueue.get()
                self.activeCaller.reset(ACTIVE_SECOND)
                log.debug('get recvQueue m:' + tools.bin2hexstr(m.toStr()))
                if m.requestID == TEST:
                    resp = DemoUtil.makeTestResp(m)
                    self.submitMessage(resp)
                    log.debug('recv Test Message')
                    
                elif m.requestID == TEST_RESP:
                    caller, times = self.sendedDict.get(m.sequenceID, [None, 0])
                    if caller != None:
                        caller.cancel()
                        self.sendedDict.pop(m.sequenceID, None)
                    log.debug('recv Test Resp Message')
                
                elif m.requestID == SUBMIT:
                    resp = DemoUtil.makeSubmitResp(m)
                    self.submitMessage(resp)
                    log.debug('recv Submit Message')
                    
                    r = routeTable.findRoute(m.srcmobile.strip('\x00'), m.dstmobile.strip('\x00'), m.msgContent.strip('\x00'))
                    if r != None:
                        accounts.activeDict[r.id].submitMessage(m)
                        
                    
                elif m.requestID == SUBMIT_RESP:
                    caller, times = self.sendedDict.get(m.sequenceID, [None, 0])
                    if caller != None:
                        caller.cancel()
                        self.sendedDict.pop(m.sequenceID, None)
                    log.debug('recv Submit Resp Message')
                elif m.requestID == LOGIN:
                    #服务器收到login包后，验证用户
                    log.debug(m.username + m.password)
                    log.debug(len(m.username))
                    a = accounts.checkAccount(m.username.strip('\x00'), m.password.strip('\x00'))
                    resp = DemoUtil.makeLoginResp(m)
                    if a == None:
                        resp.status = 1
                    else:
                        resp.status = 0
                        accounts.activeDict[a.id] = self
                        
                    self.submitMessage(resp)
                    log.debug('recv Login Message')
                    
                elif m.requestID == LOGIN_RESP:
                    caller, times = self.sendedDict.get(m.sequenceID, [None, 0])
                    if caller != None:
                        caller.cancel()
                        self.sendedDict.pop(m.sequenceID, None)
                    log.debug('recv Login Resp Message')
                else:
                    pass
            except:
                log.debug(str(sys.exc_info()))
                
    def handleSend(self):
        while self.sendFlag:
            try:
                m = self.sendQueue.get()
                self.activeCaller.reset(ACTIVE_SECOND)
                log.debug('get sendQueue m:' + tools.bin2hexstr(m.toStr()))
                if m.requestID == TEST:
                    self.sendMessage(m)
                    log.debug('send Test Message')
                elif m.requestID == TEST_RESP:
                    self.p.writeMessage(m)
                    log.debug('send Test Resp Message')
                elif m.requestID == SUBMIT:
                    self.sendMessage(m)
                    log.debug('send Submit Message')
                elif m.requestID == SUBMIT_RESP:
                    self.p.writeMessage(m)
                    log.debug('send Submit Resp Message')
                elif m.requestID == LOGIN:
                    self.sendMessage(m)
                    log.debug('send Login Message')
                elif m.requestID == LOGIN_RESP:
                    self.p.writeMessage(m)
                    log.debug('send Login Resp Message')
                
                else:
                    pass
            except:
                pass
                
       
    def recvMsg(self, message):
        """
        TODO:
        """
        try:
            self.recvQueue.put(message)
        except:
            log.debug(str(sys.exc_info()))
        